﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using Graphic = Ribbon.Core.Graphics.GraphicHelper;
using Ribbon.Core.Win32;
using System.Runtime.InteropServices;

namespace Ribbon.Core
{
    public class TextBoxDemo : Control
    {
        Win32.Caret caret = null;

        string text = "";

        public new string Text
        {
            get { return text; }
            set { text = value; }
        }

        public int SelectStart = 0;

        public int SelectLength = 0;


        private Color foreColor = Color.Black;

        public override Color ForeColor
        {
            get
            {
                return foreColor;
            }
            set
            {
                foreColor = value;
            }
        }

        public Color SelectBackColor = Color.Blue;

        public Color SelectForeColor = Color.White;

        public Color BorderColor = Color.FromArgb(100, 50, 100);

        public Color SelectBorderColor = Color.FromArgb(0, 120, 215);

        private RectangleF FontRect { get; set; }

        private StringFormat sf = new StringFormat(StringFormatFlags.NoClip);

        public int FirstDisplayIndex { get; set; }

        public bool Active;

        private float radiu;

        public float Radiu
        {
            get { return radiu; }

            set
            {
                if (value < 0)
                {
                    radiu = 0;
                }
                else
                {
                    if (radiu > this.Height / 2)
                    {
                        radiu = this.Height / 2 - 1;
                    }
                    else
                    {
                        radiu = value;
                    }
                }
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            if (this.Parent != null)
            {
                if (this.BackColor == null)
                    this.BackColor = this.Parent.BackColor;

                if (this.Font == null)
                    this.Font = Parent.Font;

                hwndSource = this.Parent.Handle;

                if (caret == null)
                {
                    caret = new Win32.Caret(this);
                }
            }
            base.OnParentChanged(e);
        }

        public TextBoxDemo()
            : base()
        {
            this.SetStyle(ControlStyles.UserPaint, true);

            this.SetStyle(ControlStyles.ResizeRedraw, true);

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            radiu = 10;

            this.text = "尔我";

            Graphic.CreateGraphics(this);

            //this.ImeMode = System.Windows.Forms.ImeMode.OnHalf;


        }

        protected override void OnGotFocus(EventArgs e)
        {
            this.CreateContext();

            base.OnGotFocus(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            //ImeContext.Enable(this.Handle);
            //Console.WriteLine();

            //{
            //    ImeMode mode = ImeContext.GetImeMode(this.Handle);

            //    Console.WriteLine(mode);

            //    ImeContext.SetImeStatus(System.Windows.Forms.ImeMode.On, this.Handle);

            //    Console.WriteLine("SetMode");

            //    mode = ImeContext.GetImeMode(this.Handle);

            //    Console.WriteLine(mode);
            //}

            //{

            //    bool open = ImeContext.IsOpen(this.Handle);

            //    Console.WriteLine(open);



            //    ImeContext.SetOpenStatus(false , this.Handle);


            //    Console.WriteLine("Open");

            //     open = ImeContext.IsOpen(this.Handle);

            //    Console.WriteLine(open);
            //}

            if (e.KeyCode == Keys.Left)
            {

            }
            else if (e.KeyCode == Keys.Right)
            {
                
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (caret != null)
            {
                caret.Show();
            }

            if (Active == false)
            {
                Active = true;

                //this.Refresh();
            }

            base.OnMouseDown(e);

            this.Focus();

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                
            }
        }
        protected override void OnMouseEnter(EventArgs e)
        {
            this.Cursor = Cursors.IBeam;

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            this.Cursor = Cursors.Arrow;
            base.OnMouseLeave(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            Point p = new Point(e.X, e.Y);

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                string str = string.Empty;

                float X = this.FontRect.X + 8;

                int index = FirstDisplayIndex;

                System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();

                st.Start();

                while (true)
                {
                    str = text[index++].ToString();//.Substring(index++, 1);

                    SizeF sizeF = Graphic.Graphics.MeasureString(str, this.Font, 2000, StringFormat.GenericTypographic);

                    float dis = X + sizeF.Width - e.X;

                    if (dis > -1e-2)
                    {
                        if ((dis - this.FontRect.X) > 1)
                            X += sizeF.Width;
                        break;
                    }

                    X += sizeF.Width;

                    if (index >= text.Length)
                    {
                        break;
                    }
                }

                if (caret != null)
                {

                    bool create = caret.Create(0, 1, (int)this.FontRect.Height);

                    bool show = caret.Show();

                    bool setPos = caret.SetPos((int)(X), (this.Height - ((int)this.FontRect.Height)) / 2);

                    //caret.SetBlinkTime(800);

                    //Console.WriteLine("Show:{0}  SetPos:{1}  X:{2}", "", setPos, X);
                }

                st.Stop();

                Console.WriteLine(st.ElapsedMilliseconds);
            }
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            Active = false;

            //if (caret != null)
            //{
            //    caret.Destroy();
            //    caret = null;
            //}

            this.Refresh();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            if (this.Font != null)
            {
                SizeF s = Graphic.Graphics.MeasureString(this.text, this.Font);

                this.FontRect = new RectangleF(5f, (this.Height - s.Height) / 2, this.Width - 2.3f, s.Height);
            }
        }

        protected override bool IsInputKey(System.Windows.Forms.Keys keyData)
        {
            return true;
        }

        protected override bool IsInputChar(char charCode)
        {
            if (Char.IsNumber(charCode) || charCode == '.')
            {
                this.text = this.text.Insert(this.SelectStart, charCode.ToString());
            }
            else //否则输入的就是  其他字符 例如：字母 标点符号  运算符  中文字等等
            {
                int nCode = (int)charCode;

                //Console.WriteLine(nCode);

                if (nCode == 8)//back
                {
                    if (this.SelectStart > 0)
                    {
                        if (this.SelectStart >= this.text.Length)
                        {

                        }
                    }
                }
                else if (nCode == 22)  //Control+V
                {

                }
                else if (nCode == 26) //Undo
                {

                }
                else if (nCode == 24)//Control+X
                {

                }
                else //input
                {
                    this.text = this.text.Insert(this.SelectStart, charCode.ToString());
                }
            }

            this.Refresh();

            return true;

            //return base.IsInputChar(charCode);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphic.Graphics.Clear(this.BackColor);

            Rectangle rec = new Rectangle(0, 0, this.Width - 1, this.Height - 1);

            //Draw border
            if (radiu > 1)
            {
                System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();

                path.AddLine(rec.X, rec.Y + rec.Height - radiu, rec.X, rec.Y + radiu);

                path.AddArc(rec.X, rec.Y, radiu, radiu, 180, 90);

                path.AddLine(rec.X + radiu, rec.Y, rec.X + rec.Width - radiu, rec.Y);

                path.AddArc(rec.X + rec.Width - radiu, rec.Y, radiu, radiu, 270, 90);

                path.AddLine(rec.X + rec.Width, rec.Y + radiu, rec.X + rec.Width, rec.Y + rec.Height - radiu);

                path.AddArc(rec.X + rec.Width - radiu, rec.Y + rec.Height - radiu, radiu, radiu, 0, 90);

                path.AddLine(rec.X + rec.Width - radiu, rec.Y + rec.Height, rec.X + radiu, rec.Y + rec.Height);

                path.AddArc(rec.X, rec.Y + rec.Height - radiu, radiu, radiu, 90, 90);

                path.CloseFigure();

                using (Pen p = new Pen(Active ? this.SelectBorderColor : this.BorderColor, 1.5f))
                {
                    Graphic.Graphics.DrawPath(p, path);
                }

                using (path) { }
            }
            else
            {
                using (Pen p = new Pen(Active ? this.SelectBorderColor : this.BorderColor))
                {
                    Graphic.Graphics.DrawRectangle(p, rec);
                }
            }

            //using (Pen p = new Pen(Active ? this.SelectBorderColor : this.BorderColor))
            //{
            //    int startX = 0;

            //    for (int i = 0; i < 10; i++)
            //    {
            //        Graphic.Graphics.DrawLine(p, i * 10 + startX, 0, i * 10 + startX, this.Height);
            //    }
            //}
            using (Brush bru = new SolidBrush(this.ForeColor))
            {
                Graphic.Graphics.DrawString(text, this.Font, bru, this.FontRect, sf);
            }
            //没有选择的文字
            if (SelectLength < 1)
            {

            }
            //有选择的文字
            else
            {

            }

            Graphic.Buffer.Render(e.Graphics);
        }


        IntPtr hwndSource;
        IntPtr defaultImeWnd;
        IntPtr currentContext;
        IntPtr previousContext;

        private void CreateContext()
        {
            ClearContext();

            defaultImeWnd = ImeNative.ImmGetDefaultIMEWnd(IntPtr.Zero);

            if (defaultImeWnd == IntPtr.Zero)
            {
                // 如果拿到了空的默认 IME 窗口了，那么此时也许是作为嵌套窗口放入到另一个进程的窗口

                // 拿不到就需要刷新一下。否则微软拼音输入法将在屏幕的左上角上

                // 尝试通过 _hwndSource 也就是文本所在的窗口去获取
                defaultImeWnd = ImeNative.ImmGetDefaultIMEWnd(hwndSource);

                if (defaultImeWnd == IntPtr.Zero)
                {
                    Console.WriteLine("");
                }
            }

            currentContext = ImeNative.ImmGetContext(defaultImeWnd);

            if (currentContext == IntPtr.Zero)
            {
                currentContext = ImeNative.ImmGetContext(hwndSource);
            }

            previousContext = ImeNative.ImmAssociateContext(hwndSource, currentContext);

            UpdateCompositionWindow();
        }

        private void ClearContext()
        {
            ImeNative.ImmAssociateContext(hwndSource, previousContext);

            ImeNative.ImmReleaseContext(defaultImeWnd, currentContext);
        }

        public void UpdateCompositionWindow()
        {
            if (currentContext == IntPtr.Zero)
            {
                CreateContext();

                if (currentContext == IntPtr.Zero)
                {
                    return;
                }
            }

            // 这是判断在系统版本大于 Win7 的系统，如 Win10 系统上，使用微软拼音输入法的逻辑
            // 微软拼音输入法在几个版本，需要修改 Y 坐标，加上输入的行高才可以。但是在一些 Win10 版本，通过补丁又修了这个问题
            //_isSoftwarePinYinOverWin7 = IsMsInputMethodOverWin7();
            //上面判断微软拼音的方法，会导致方法被切片，从而在快速得到焦点和失去焦点时，失去焦点清理的代码会先于此函数执行，导致引发错误

            SetCompositionFont();

            SetCompositionWindow();
        }

        private void SetCompositionFont()
        {
            var lf = new ImeNative.LOGFONT();

            lf.lfFaceName = this.Font.Name;

            lf.lfHeight = this.Font.Height;

            var hIMC = currentContext;

            var GCS_COMPSTR = 8;

            var length = ImeNative.ImmGetCompositionString(hIMC, GCS_COMPSTR, null, 0);

            if (length > 0)
            {
                var target = new byte[length];

                var count = ImeNative.ImmGetCompositionString(hIMC, GCS_COMPSTR, target, length);

                if (count > 0)
                {
                    var inputString = Encoding.Default.GetString(target);

                    if (string.IsNullOrWhiteSpace(inputString))
                    {
                        lf.lfWidth = 1;
                    }
                }
            }

            ImeNative.ImmSetCompositionFont(hIMC, ref lf);
        }

        private void SetCompositionWindow()
        {
            var hIMC = currentContext;

            //HwndSource source = _hwndSource ?? throw new ArgumentNullException(nameof(_hwndSource));

            //var textEditorLeftTop = Editor.GetTextEditorLeftTop();
            //var caretLeftTop = Editor.GetCaretLeftTop();

            //var transformToAncestor = Editor.TransformToAncestor(source.RootVisual);

            //var textEditorLeftTopForRootVisual = transformToAncestor.Transform(textEditorLeftTop);
            //var caretLeftTopForRootVisual = transformToAncestor.Transform(caretLeftTop);

            ////解决surface上输入法光标位置不正确
            ////现象是surface上光标的位置需要乘以2才能正确，普通电脑上没有这个问题
            ////且此问题与DPI无关，目前用CaretWidth可以有效判断
            //caretLeftTopForRootVisual = new Point(caretLeftTopForRootVisual.X / SystemParameters.CaretWidth,
            //    caretLeftTopForRootVisual.Y / SystemParameters.CaretWidth);

            //const int CFS_DEFAULT = 0x0000;
            //const int CFS_RECT = 0x0001;
            const int CFS_POINT = 0x0002;
            //const int CFS_FORCE_POSITION = 0x0020;
            //const int CFS_EXCLUDE = 0x0080;
            //const int CFS_CANDIDATEPOS = 0x0040;

            var form = new ImeNative.CompositionForm();
            form.dwStyle = CFS_POINT;
            form.ptCurrentPos.x = (int)0;
            form.ptCurrentPos.y = (int)this.Height / 2;
            //if (_isSoftwarePinYinOverWin7)
            //{
            //    form.ptCurrentPos.y += (int) characterBounds.Height;
            //}

            ImeNative.ImmSetCompositionWindow(hIMC, ref form);
        }
    }
}
